package com.kobeliu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.kobeliu.api.feign.CompanyMicroFeign;
import com.kobeliu.api.feign.UsersMicroServiceFeign;
import com.kobeliu.base.BaseInfoProperties;
import com.kobeliu.enums.JobStatus;
import com.kobeliu.exceptions.GraceException;
import com.kobeliu.mapper.JobMapper;
import com.kobeliu.pojo.Industry;
import com.kobeliu.pojo.Job;
import com.kobeliu.pojo.bo.EditJobBO;
import com.kobeliu.pojo.bo.SearchBO;
import com.kobeliu.pojo.bo.SearchJobsBO;
import com.kobeliu.pojo.vo.*;
import com.kobeliu.result.GraceJSONResult;
import com.kobeliu.result.ResponseStatusEnum;
import com.kobeliu.service.JobService;
import com.kobeliu.utils.GsonUtils;
import com.kobeliu.utils.PagedGridResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jboss.marshalling.TraceInformation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.batch.JobExecutionEvent;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.management.remote.rmi._RMIConnection_Stub;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
@Slf4j
public class JobServiceImpl extends BaseInfoProperties implements JobService {

    @Autowired
    private JobMapper jobMapper;

    @Autowired
    private UsersMicroServiceFeign usersFeign;

    @Autowired
    private CompanyMicroFeign companyFeign;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Override
    public PagedGridResult hrJobList(String hrId, String companyId, Integer page, Integer limit,Integer status) {

        PageHelper.startPage(page,limit);

        List<Job> jobs = jobMapper.selectList(new QueryWrapper<Job>()
                .eq("hr_id",hrId)
                .eq("company_id",companyId)
                .eq("status",status));

        return setterPagedGrid(jobs,page);
    }

    @Override
    public PagedGridResult hrJobAllList(String hrId, String companyId, Integer page, Integer limit) {

        Integer[] states = new Integer[]{JobStatus.OPEN.type,JobStatus.CLOSE.type,JobStatus.DELETE.type};

        PageHelper.startPage(page,limit);
//        PageHelper.startPage(page,7);

        List<Job> jobs = jobMapper.selectList(new QueryWrapper<Job>()
                .eq("hr_id",hrId)
                .eq("company_id",companyId)
                .in("status",states));

        return setterPagedGrid(jobs,page);
    }

    @Override
    public Job jobDetail(String hrId, String companyId, String jobId) {
        Job job = jobMapper.selectOne(new QueryWrapper<Job>()
                .eq("id",jobId)
                .eq("hr_id",hrId)
                .eq("company_id",companyId));

        redis.set(REDIS_JOB_DETAIL +
                ":"+companyId+
                ":"+hrId+":"+
                jobId
                ,new Gson().toJson(job));
        return job;
    }

    @Transactional
    @Override
    public void modifyJob(EditJobBO bo) {

        if(bo == null){
            GraceException.display(ResponseStatusEnum.JOB_VARIABLES_ERROR);
        }

        Job pending = new Job();
        BeanUtils.copyProperties(bo,pending);
        pending.setUpdatedTime(LocalDateTime.now());

        if(bo.getId() == null || "".equals(bo.getId())){
            //代表此时是新增
            pending.setCreateTime(LocalDateTime.now());
            pending.setStatus(JobStatus.OPEN.type);
            jobMapper.insert(pending);
        }else{
            jobMapper.updateById(pending);
        }

        redis.del(REDIS_JOB_DETAIL +
                ":"+bo.getCompanyId()+
                ":"+bo.getHrId()+
                ":"+ pending.getId());
    }

    @Transactional
    @Override
    public void closeJob(String hrId, String companyId, String jobId) {

        Job pending = new Job();
        pending.setId(jobId);
        pending.setUpdatedTime(LocalDateTime.now());
        pending.setStatus(JobStatus.CLOSE.type);

        jobMapper.updateById(pending);

        redis.del(REDIS_JOB_DETAIL +
                ":"+companyId+
                ":"+hrId+":"+
                jobId);
    }
    //changeToHR

    @Transactional
    @Override
    public void openJob(String hrId, String companyId, String jobId) {
        Job pending = new Job();
        pending.setId(jobId);
        pending.setUpdatedTime(LocalDateTime.now());
        pending.setStatus(JobStatus.OPEN.type);

        jobMapper.updateById(pending);

        redis.del(REDIS_JOB_DETAIL +
                ":"+companyId+
                ":"+hrId+":"+
                jobId);
    }

    @Override
    public PagedGridResult adminJobList(String companyId,Integer page, Integer limit) {

        PageHelper.startPage(page,limit);
        Integer[] states = new Integer[]{JobStatus.OPEN.type,JobStatus.CLOSE.type,JobStatus.DELETE.type};

        List<Job> jobs = jobMapper.selectList(new QueryWrapper<Job>()
                .eq("company_Id",companyId)
                .in("status",states)
                .orderByAsc("updated_time"));

        return setterPagedGrid(jobs,page);
    }

    @Override
    public Job adminJobDetail(String jobId) {
        return jobMapper.selectById(jobId);
    }

    @Override
    public PagedGridResult searchJobs(SearchJobsBO bo, Integer page, Integer limit,JobStatus status) {

        PageHelper.startPage(page,limit);

        String jobType = bo.getJobType();
        String jobName = bo.getJobName();
        String city = bo.getCity();
        Integer beginSalary = bo.getBeginSalary();
        Integer endSalary = bo.getEndSalary();

        QueryWrapper<Job> jobQueryWrapper = new QueryWrapper<>();

        if(StringUtils.isNotBlank(jobName)){
            jobQueryWrapper.like("job_name",jobName);
        }
        if(StringUtils.isNotBlank(jobType)){
            jobQueryWrapper.like("job_type",jobType);
        }
        if(StringUtils.isNotBlank(city)){
            jobQueryWrapper.like("city",city);
        }
        if(beginSalary != null && beginSalary > 0 && endSalary > 0){
            jobQueryWrapper.ge("end_salary",beginSalary);
        }

        if(status != null){
            jobQueryWrapper.eq("status",status.type);
        }

        //拿取单页的数据
        PagedGridResult result = setterPagedGrid(jobMapper.selectList(jobQueryWrapper), page);
        List<?> jobs =result.getRows();

        List<SearchJobsVO> searchJobsVOS = jobs.stream().map(obj -> {
            Job j = (Job) obj;
            SearchJobsVO v = new SearchJobsVO();
            BeanUtils.copyProperties(j, v);
            return v;
        }).collect(Collectors.toList());

        //获取UserVO && companyInfoVO

        List<String> userIds = new ArrayList<>();
        List<String> companyIds = new ArrayList<>();



        for(Object o :jobs){
            Job job = (Job) o;
            userIds.add(job.getHrId());
            companyIds.add(job.getCompanyId());
        }

        if(userIds.size()>0){
            SearchBO searchBO = new SearchBO();
            searchBO.setCompanyIds(companyIds);
            searchBO.setUserIds(userIds);

            GraceJSONResult companyInfosResult = companyFeign.getCompanyInfos(searchBO);
            List<CompanyInfoVO> companyInfos =
                    new Gson().fromJson(companyInfosResult.getData().toString(),
                            new TypeToken<List<CompanyInfoVO>>() {}.getType());
            GraceJSONResult userInfosResult = usersFeign.getUserInfos(searchBO);
            List<UsersVO> userInfos =
                    new Gson().fromJson(userInfosResult.getData().toString(),
                            new TypeToken<List<UsersVO>>() {}.getType());


            //拿取userVO
            for(SearchJobsVO v: searchJobsVOS){
                for(UsersVO u: userInfos){
                    if(v.getHrId().equals(u.getId())){
                        v.setUsersVO(u);
                    }
                }
            }

            //拿取companyInfoVO
            for(SearchJobsVO v: searchJobsVOS){
                for(CompanyInfoVO c: companyInfos){
                    if(v.getCompanyId().equals(c.getCompanyId())){
                        v.setCompanyInfoVO(c);
                    }
                }
            }
        }

        result.setRows(searchJobsVOS);
        return result;
    }

    @Override
    public long getJobCounts(String hrId) {

        GraceJSONResult info = usersFeign.getInfo(hrId);
        UsersVO vo = new Gson().fromJson(info.getData().toString(),UsersVO.class);
        QueryWrapper<Job> qw = new QueryWrapper<Job>().eq("hr_id", hrId);

        String companyId = vo.getHrInWhichCompanyId();
        if(companyId != null){
            String countStr = redis.get(HR_ALL_JOB_COUNTS+":"+hrId+":"+companyId);
            if(countStr !=null){
                return Long.parseLong(countStr);
            }
            qw.eq("company_id",companyId);
        }
        Long counts = jobMapper.selectCount(qw);
        redis.set(HR_ALL_JOB_COUNTS+":"+hrId+":"+companyId,String.valueOf(counts),60*1000);

        return counts;
    }

    @Override
    public List<SearchJobsVO> selectJobDetailsByIds(List<String> jobIds, JobStatus status) {

        //先查job数据
        QueryWrapper<Job> qw = new QueryWrapper<>();
        qw.in("id",jobIds);
        if(status != null){
            qw.eq("status",status.type);
        }
        List<Job> jobs = jobMapper.selectList(qw);

        List<String> companyIds = jobs.stream().map(Job::getCompanyId).collect(Collectors.toList());
        List<String> hrIds = jobs.stream().map(Job::getHrId).collect(Collectors.toList());

        SearchBO searchBO = new SearchBO();
        searchBO.setUserIds(hrIds);
        searchBO.setCompanyIds(companyIds);

        //根据companyId去company服务中拿取company的数据
        //根据hrId去user服务中拿取hr的数据
        ResultVO resultVO = new ResultVO();
        //不串行执行 使用线程池并行
        CompletableFuture<Void> companyFuture = CompletableFuture.runAsync(() ->{
            GraceJSONResult companyInfos = companyFeign.getCompanyInfos(searchBO);
            resultVO.setCompanyInfos(new Gson().fromJson(companyInfos.getData().toString(),
                    new TypeToken<List<CompanyInfoVO>>() {}.getType() ));

        },threadPoolExecutor);

        CompletableFuture<Void> hrFuture = CompletableFuture.runAsync(() ->{
            GraceJSONResult userInfos = usersFeign.getUserInfos(searchBO);

            resultVO.setUsersVOS(new Gson().fromJson(userInfos.getData().toString(),
                    new TypeToken<List<UsersVO>>() {}.getType() ));
        },threadPoolExecutor);

        try{
            //阻塞等待完成
            CompletableFuture.allOf(companyFuture,hrFuture).get();
        }catch(Exception e){
            e.printStackTrace();
            GraceException.display(ResponseStatusEnum.ARTICLE_COVER_NOT_EXIST_ERROR);
        }


        //组装数据
        List<SearchJobsVO> vos = jobs.stream().map(job -> {
            SearchJobsVO searchJobsVO = new SearchJobsVO();
            BeanUtils.copyProperties(job,searchJobsVO);
            return searchJobsVO;
        }).collect(Collectors.toList());



        //走并发
        for(UsersVO v:resultVO.getUsersVOS()){
            for(SearchJobsVO searchJobsVO:vos){
                if(searchJobsVO.getId().equals(v.getId())){
                    searchJobsVO.setUsersVO(v);
                }
            }
        }

        for(CompanyInfoVO v:resultVO.getCompanyInfos()){
            for(SearchJobsVO searchJobsVO:vos){
                if(searchJobsVO.getCompanyId().equals(v.getCompanyId())){
                    searchJobsVO.setCompanyInfoVO(v);
                }
            }
        }

        return vos;
    }

}
